using System;
using System.Collections.Concurrent;
using System.Threading;
using Jarvis.Server.Location;
using Ninject.Extensions.Logging;

namespace Jarvis.Server.Actions
{
    public class ActionRunner : IActionRunner
    {
        private readonly BlockingCollection<Domain.Location> _eventsPending;
        private readonly ILocationProvider _locationProvider;
        private readonly Thread _actionRunnerThread;
        private readonly ILogger _logger;

        public ActionRunner(ILocationProvider locationProvider, ILoggerFactory loggerFactory)
        {
            _logger = loggerFactory.GetCurrentClassLogger();
            _locationProvider = locationProvider;
            _eventsPending =new BlockingCollection<Domain.Location>();
            _actionRunnerThread = new Thread(ActionRunnerThreadStart)
                                      {Name = "Action Runner Thread", IsBackground = true};
            _actionRunnerThread.Start();
        }

        private void ActionRunnerThreadStart()
        {
            while(true)
            {
                var location = _eventsPending.Take(); // the thread will block until an event is ready
                var actionsToRun = location.Actions;

                foreach (var action in actionsToRun)
                {
                    _logger.Trace("Executing action {0}",action.Name);
                    action.Execute();
                }
            }
        }

        #region Implementation of IActionRunner

        public void Start()
        {
            IsRunning = true;
            _locationProvider.CurrentLocationChanged += CurrentLocationChanged;
        }

        public void Stop()
        {
            _locationProvider.CurrentLocationChanged -= CurrentLocationChanged;
            IsRunning = false;
        }

        void CurrentLocationChanged(object sender, LocationEventArgs e)
        {
            _logger.Trace("Adding Action to pendingEventsList");
            _eventsPending.Add(e.Location);
        }

        public bool IsRunning { get; private set; }

        #endregion
    }
}